/**
  ******************************************************************************
  * @file    backwork.c
  * @author  Dragon.Chen
  * @version V1.000
  * @date    04-15-2018
  * @brief      业务逻辑函数的封装
  * @project linux client
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; COPYRIGHT 2018 上海今中网络科技有限公司 </center></h2>
  ******************************************************************************
  */

#include "backwork.h"

static const char * openvpn_config_path = "./config/sonicomEncryptVpn.conf";     //!! remeber to optimize it!!
static int	        PackHead         = 0;
/////////////////old edtion/////////////////////
// ********************************** heartbag **********************************
void *heartbeat_timeout(void *args)
{
    CLIENT_INFO_T *clientInfo = (CLIENT_INFO_T *)args;

	for (HeartbeatTime=HeartbeatTimeout; HeartbeatTime>0; HeartbeatTime--)
	{
		if (ServerLoop == TRUE)
		{
			if (ServerAlive == TRUE)
			{
				return NULL;
			}
			else
			{
				sleep(1);
			}
		}
		else
		{
			return NULL;
		}
	}

    if (clientInfo->nLostHeartbeat < 1)
	{
		clientInfo->nLostHeartbeat++;
		EventSelect = 1;
	}
	else
	{
        //RetvalMessage = ERROR_NETWORK_EXCEPTION;
        ServerLoop = FALSE;
	}

	return NULL;
}

/**
  * @brief   接收heartbag结果
  * @param   arg1 客户端信息结构体
  * @retval  成功返回0，失败返回-1，接收未完成返回1
  */
int receive_result_of_heartbeat(CLIENT_INFO_T *clientInfo)
{
	int retval;

	if (clientInfo->bufferFirst == YES) /*接收数据头部*/
	{
		ZeroMemory(clientInfo->buffer, SOCK_RECV_MAXBUF);
		clientInfo->bufferPosition = 0;
		retval = recv(clientInfo->serverFd, clientInfo->buffer, CLIENT_DATA_PACK_HEADLEN, 0);
		if ( (retval != CLIENT_DATA_PACK_HEADLEN) || ((clientInfo->bufferLength = atoi(clientInfo->buffer)) == 0) )
		{
			goto finish;
		}
	}

	while (TRUE)  /*接收数据*/
	{
		retval = recv(clientInfo->serverFd, clientInfo->buffer + clientInfo->bufferPosition, clientInfo->bufferLength - clientInfo->bufferPosition, 0);
		if (retval <0)
		{
			if (errno == EINTR)
			{
				continue;
			}
			else if (errno == EAGAIN || errno == EWOULDBLOCK)
			{
				clientInfo->bufferFirst = NO;
				return 1;
			}
			else
			{
				goto finish;
			}
		}
		else if (retval == 0)
		{
			goto finish;
		}

		clientInfo->bufferPosition += retval;
		if (clientInfo->bufferPosition < clientInfo->bufferLength)
		{
			continue;
		}
		else if (clientInfo->bufferPosition == clientInfo->bufferLength)
		{
			break;
		}
		else
		{
			goto finish;
		}
	}

	ServerAlive = TRUE;
	for (; HeartbeatTime>0; HeartbeatTime--)				// 每隔30秒发个心跳包
	{
		if (ServerLoop)
		{
			sleep(1);
		}
		else
		{
			goto finish;
		}
	}

	clientInfo->nLostHeartbeat = 0;
	return 0;

finish :
	if (clientInfo->nLostHeartbeat < 1)
	{
		clientInfo->nLostHeartbeat++;
		return 0;
	}
	else
	{
		return -1;
	}
}

/**
  * @brief   发送heartbag请求
  * @param   arg1 客户端信息结构体
  * @retval  成功返回0，失败返回-1，发送未完成返回1
  */
int send_request_of_heartbeat(CLIENT_INFO_T *clientInfo)
{
    //int         i = 0;
	int		    retval;
	pthread_t   tid;

	if (clientInfo->bufferFirst == YES)
	{
		ZeroMemory(clientInfo->buffer, SOCK_RECV_MAXBUF);
		sprintf(clientInfo->buffer, "%4d%4d%s", 4, IDX_VPN_HEARTBEAT, "");
		clientInfo->bufferLength = strlen(clientInfo->buffer);
		clientInfo->bufferPosition = 0;
	}

	while (TRUE)
	{
		retval = send(clientInfo->serverFd, clientInfo->buffer + clientInfo->bufferPosition, clientInfo->bufferLength - clientInfo->bufferPosition, 0);
		if (retval < 0)
		{
			if (errno == EINTR)
			{
				continue;
			}
			else if (errno == EAGAIN || errno == EWOULDBLOCK)
			{
				clientInfo->bufferFirst = NO;
				return 1;
			}
			else
			{
				return -1;
			}
		}
		else if (retval == 0)
		{
			return -1;
		}

		clientInfo->bufferPosition += retval;
		if (clientInfo->bufferPosition < clientInfo->bufferLength)
		{
			continue;
		}
		else if (clientInfo->bufferPosition == clientInfo->bufferLength)
		{
			clientInfo->bufferFirst = YES;
			ServerAlive = FALSE;
            pthread_create(&tid, NULL, (void *)heartbeat_timeout, clientInfo);
			usleep(100000);
			return 0;
		}
		else
		{
			return -1;
		}
	}
}

/************************************** HEARTBEAT_TIMEOUT *************************************/
/**
  * @brief   接收heartbag timeout结果
  * @param   arg1 客户端信息结构体
  * @retval  成功返回0，失败返回-1，接收未完成返回1
  */
int receive_result_of_heartbeat_timeout(CLIENT_INFO_T *clientInfo)
{
	int			retval;
	DATA_PACK_T  *datapack;

	RECV_COMMAND(clientInfo->serverFd);

	if (datapack->head != IDX_VPN_HEARTBEAT_TIMEOUT)
	{
		return -1;
	}

	HeartbeatTimeout = atoi(datapack->buffer);
	if (HeartbeatTimeout == 0)
		return -1;

	HeartbeatTimeout = HeartbeatTimeout - 5;
	clientInfo->relayData.data = NULL;
	clientInfo->relayData.head = IDX_VPN_HEARTBEAT;
	return 0;
}

/**
  * @brief   发送heartbag请求
  * @param   arg1 客户端信息结构体
  * @retval  成功返回0，失败返回-1，发送未完成返回1
  */
int send_request_of_heartbeat_timeout(CLIENT_INFO_T *clientInfo)
{
	int		retval;

	if (clientInfo->bufferFirst == YES)
	{
		sprintf(clientInfo->buffer, "%4d%4d", 4, IDX_VPN_HEARTBEAT_TIMEOUT);
		clientInfo->bufferLength = strlen(clientInfo->buffer);
		clientInfo->bufferPosition = 0;
	}

	SEND_COMMAND(clientInfo->serverFd);
}


///**
//  * @brief   接收协商的数字，决定是否启动服务
//  * @param   arg1 客户端信息结构体
//  * @retval  启动返回0， 失败返回-1，
//  */
//int start_service_type(CLIENT_INFO_T * clientInfo)
//{
//    // 10 < x < 99 ok ,560 < x < 650 noOk
//
//    char buf[64] = {0};
//    int  decodeNum;
//    int ret = 0;
//    //
//    strcpy(buf, clientInfo->relayData.data);
//    //base64_decode(clientInfo->relayData.data, (void *)buf, 64);
//    decodeNum = atoi((const char *)buf);
//    if(decodeNum <= 99 && decodeNum >= 10)
//    {
//        ret = 1;
//        goto finish;
//    }
//    else if(decodeNum <= 650 && decodeNum >= 560)
//    {
//        ret = 2;
//        goto finish;
//    }
//    else
//    {
//        ret = -1;
//        goto finish;
//    }
//
//
//finish:
//    return ret;
//
//}
//

///**************************************** utunnel ***************************************/
///**
//  * @brief   启动所有的服务
//  * @param   NULL
//  * @retval
//  */
//void startup_all_services(CLIENT_INFO_T *clientInfo)
//{
//	FILE   *fp = NULL;
//    if(ServiceStartTriger == 1 )
//    {
//        /// 启动所有服务
//        	if ((PACK_HEAD)PackHead == IDX_VPN_OPENVPN)
//        	{
//        		if ((fp = fopen(openvpn_config_path, "rt")) != NULL)
//        		{
//        			send_message_to_java(STARTUP_MINIVPN);
//        		}
//        	}
//        	else if ((PACK_HEAD)PackHead == IDX_VPN_STUNNEL)
//        	{
//        		if (access(stunnel_config_path, 0) == 0)
//        		{
//        			send_message_to_java(STARTUP_STUNNEL);
//        		}
//
//        		if (access(utunnel_config_path, 0) == 0)
//        		{
//        			send_message_to_java(STARTUP_UTUNNEL);
//        		}
//        	}
//        	else /* both service */
//        	{
//        		if (clientInfo->appType == 1 || /*openvpn*/
//        			clientInfo->appType == 3 || /*both   */
//        			clientInfo->appType == 4)   /*both   */
//        		{
//        			send_message_to_java(STARTUP_MINIVPN);
//        		}
//
//        		if (clientInfo->appType == 2 || /*stunnel*/
//        			clientInfo->appType == 3 || /*both   */
//        			clientInfo->appType == 4)   /*both   */
//        		{
//                    if (access(stunnel_config_path, 0) == 0)
//                    {
//                        send_message_to_java(STARTUP_STUNNEL);
//                    }
//
//                    if (access(utunnel_config_path, 0) == 0)
//                    {
//                        send_message_to_java(STARTUP_UTUNNEL);
//                    }
//        		}
//        	}
//    }
//
//	clientInfo->relayData.head = IDX_VPN_HEARTBEAT_TIMEOUT;
//	send_message_to_java(SUCCESS_LOGINED_SERVER);
//}
//
///**
//  * @brief   获取utunnel配置信息
//  * @param   arg1 客户端信息结构体
//  * @retval  0 成功  -1 失败
//  */
//int generate_utunnel_config(CLIENT_INFO_T *clientInfo)
//{
//	char  buf1[512], buf2[512];
//	FILE *fp1, *fp2;
//	char *savep, *temp1, *temp2, *temp3, *temp4;
//	char *utunnelInfo = (char *)clientInfo->relayData.data;
//
//    if ((utunnelInfo == NULL) || (strlen(utunnelInfo) == 0))
//    {
//        __android_log_write(ANDROID_LOG_ERROR, "dragon", "服务器下发utunnel规则有误");
//        return -1;
//    }
//
//    if (streql(utunnelInfo, VPN_RULE_NULL))
//    {
//        return 0;
//    }
//
//    /* 将配置信息保存到文件，格式为:
//       timeout:encrypt
//       mobileName:clientPort:vpnPort
//       ...
//    */
//	// timeout:encrypt;测试2:30001:10002:4;test3:30003:10003:4;...
//	if ((fp1 = fopen(utunnel_recv_path, "wt")) == NULL)
//	{
//		return -1;
//	}
//
//	temp1 = strtok_r(utunnelInfo, ":", &savep);
//	if (temp1 == NULL)
//        return -1;
//	fputs(temp1, fp1);
//	fputs(":", fp1);
//	temp1 = strtok_r(NULL, ";", &savep);
//	if (temp1 == NULL)
//        return -1;
//	fputs(temp1, fp1);
//	fputs("\n", fp1);
//
//	temp1 = strtok_r(NULL, ";", &savep);
//	while (temp1 != NULL)
//	{
//		fputs(temp1, fp1);
//		fputs("\n", fp1);
//		temp1 = strtok_r(NULL, ";", &savep);
//	}
//	fflush(fp1);
//	fclose(fp1);
//
//    /* 将配置信息保存到文件，格式为正式配置文件格式 */
//	fp1 = fopen(utunnel_recv_path, "rt");
//	fp2 = fopen(utunnel_config_path, "wt");
//	if (fp1 == NULL || fp2 == NULL)
//		return -1;
//
//    /// 配置信息头部
//	ZeroMemory(buf1, 512);
//	if (fgets(buf1, 512, fp1))
//	{
//		temp1 = strtok_r(buf1, ":", &savep);
//		if (temp1 == NULL)
//            return -1;
//		temp2 = strtok_r(NULL, ":", &savep);
//		if (temp2 == NULL)
//            return -1;
//		ZeroMemory(buf2, 512);
//		snprintf(buf2, 512,
//        	    "LogPath = %sutunnel.log" "\n"
//                "PidPath = %sutunnel.pid" "\n"
//                "Timeout = %s"			"\n"
//                "Daemon  = 1"			"\n"
//                "Server  = 0"			"\n"
//                "Encrypt = %s"			"\n"
//										"\n",
//				client_config_path, client_config_path, temp1, temp2 );
//		fputs(buf2, fp2);
//		ZeroMemory(buf1, 512);
//	}
//	   /// 服务信息
//	ZeroMemory(buf1, 512);
//	while (fgets(buf1, 512, fp1) )
//	{
//		temp1 = strtok_r(buf1, ":", &savep);
//		if (temp1 == NULL)
//            return -1;
//		temp2 = strtok_r(NULL, ":", &savep);
//		if (temp2 == NULL)
//            return -1;
//		temp3 = strtok_r(NULL, ":", &savep);
//		if (temp3 == NULL)
//            return -1;
//		temp4 = strtok_r(NULL, ":", &savep);
//		if (temp4 == NULL)
//            return -1;
//
//		ZeroMemory(buf2, 512);
//		snprintf(buf2, 512,
//				"[%s]"                      "\n"
//				"accept  = 0.0.0.0:%s"      "\n"
//				"connect = %s:%s"           "\n"
//				"maxcons = %s"              "\n",
//				temp1, temp2, clientInfo->serverIp, temp3, temp4);
//		fputs(buf2, fp2);
//		ZeroMemory(buf1, 512);
//	}
//
//	fclose(fp1);
//	fflush(fp2);
//	fclose(fp2);
//	return 0;
//}
//
///**
//  * @brief   接收utunnel结果
//  * @param   arg1 客户端信息结构体
//  * @retval  成功返回0， 失败返回-1， 接收未完成返回1
//  */
//int receive_result_of_utunnel(CLIENT_INFO_T *clientInfo)
//{
//	int	  retval;
//
//	/// 接收openvpn配置
//	RECV_FILE(clientInfo->serverFd);
//
//	clientInfo->relayData.data = clientInfo->fileInfo.buffer+4;
//	retval = generate_utunnel_config(clientInfo);
//	startup_all_services(clientInfo);
//
//cleanup:
//	if (clientInfo->fileInfo.buffer)
//	{
//		free(clientInfo->fileInfo.buffer);
//		clientInfo->fileInfo.buffer   = NULL;
//		clientInfo->fileInfo.length   = 0;
//		clientInfo->fileInfo.position = 0;
//	}
//
//	return 0;
//}
//
///**
//  * @brief   发送utunnel请求
//  * @param   arg1 客户端信息结构体
//  * @retval  成功返回0，失败返回-1，发送未完成返回1
//  */
//int send_request_of_utunnel(CLIENT_INFO_T *clientInfo)
//{
//	int retval;
//
//	if (clientInfo->bufferFirst == YES)
//	{
//		ZeroMemory(clientInfo->buffer, SOCK_RECV_MAXBUF);
//		sprintf(clientInfo->buffer, "%4d%4d", 4, IDX_VPN_UTUNNEL);
//		clientInfo->bufferLength = strlen(clientInfo->buffer);
//		clientInfo->bufferPosition = 0;
//	}
//
//	SEND_COMMAND(clientInfo->serverFd);
//}
//
///**************************************** stunnel ***************************************/
///**
//  * @brief   获取stunnel配置信息
//  * @param   arg1 客户端信息结构体
//  * @retval  成功生成规则返回0, 失败返回-1
//  */
//int generate_stunnel_config(CLIENT_INFO_T *clientInfo)
//{
//	char  buf1[512], buf2[512];
//	FILE *fp1, *fp2;
//	char *savep, *temp1, *temp2, *temp3;
//	char *stunnelInfo = (char *)clientInfo->relayData.data;
//
//	if ((stunnelInfo == NULL) || (strlen(stunnelInfo) == 0))
//    {
//        return -1;
//    }
//
//    if (streql(stunnelInfo, VPN_RULE_NULL))
//    {
//		return 0;
//	}
//
//    /* 将配置信息保存到文件，格式为:
//       RC4-MD5:zlib
//       mobileName:clientPort:vpnPort
//       ...
//    */
//	/// RC4-MD5:zlib;测试2:30001:10002;test3:30003:10003
//	if ((fp1 = fopen(stunnel_recv_path, "wt")) == NULL)
//	{
//		return -1;
//	}
//
//	temp1 = strtok_r(stunnelInfo, ":", &savep);
//	if (temp1 == NULL)
//        return -1;
//	fputs(temp1, fp1);
//	fputs(":", fp1);
//	temp1 = strtok_r(NULL, ";", &savep);
//	if (temp1 == NULL)
//        return -1;
//	fputs(temp1, fp1);
//	fputs("\n", fp1);
//
//	temp1 = strtok_r(NULL, ";", &savep);
//	while (temp1 != NULL)
//	{
//		fputs(temp1, fp1);
//		fputs("\n", fp1);
//		temp1 = strtok_r(NULL, ";", &savep);
//	}
//	fclose(fp1);
//
//    /* 将配置信息保存到文件，格式为正式配置文件格式 */
//	fp1 = fopen(stunnel_recv_path, "rt");
//	fp2 = fopen(stunnel_config_path, "wt");
//	if (fp1 == NULL || fp2 == NULL)
//		return -1;
//
//	/// 配置信息头部
//	ZeroMemory(buf1, 512);
//	if (fgets(buf1, 512, fp1) )
//	{
//		temp1 = strtok_r(buf1, ":", &savep);
//		if (temp1 == NULL)
//            return -1;
//		temp2 = strtok_r(NULL, ":", &savep);
//		if (temp2 == NULL)
//		    return -1;
//		ZeroMemory(buf2, 512);
//		sprintf(buf2,
//				"client = yes"				"\n"
//				"socket = l:TCP_NODELAY=1"	"\n"
//				"socket = r:TCP_NODELAY=1"	"\n"
//				"ciphers = %s"				"\n"
//				"compression = %s"			"\n"
//                 "pid = %sstunnel.pid\n",
//				temp1, temp2, client_config_path);
//		fputs(buf2, fp2);
//		ZeroMemory(buf1, 512);
//	}
//
//    /// 服务信息
//	ZeroMemory(buf1, 512);
//	while ( fgets(buf1, 512, fp1) )
//	{
//		temp1 = strtok_r(buf1, ":", &savep);
//		if (temp1 == NULL)
//            return -1;
//		temp2 = strtok_r(NULL, ":", &savep);
//		if (temp2 == NULL)
//            return -1;
//		temp3 = strtok_r(NULL, ":", &savep);
//		if (temp3 == NULL)
//            return -1;
//
//		ZeroMemory(buf2, 512);
//		snprintf(buf2, 512,
//				"[%s]"					"\n"
//				"accept = 127.0.0.1:%s"	"\n"
//				"connect = %s:%s"		"\n",
//				temp1, temp2, clientInfo->serverIp, temp3);
//		fputs(buf2, fp2);
//		ZeroMemory(buf1, 512);
//	}
//
//	fclose(fp1);
//	fclose(fp2);
//
//	return 0;
//}
//
///**
//  * @brief   接收stunnel结果
//  * @param   arg1 客户端信息结构体
//  * @retval  成功返回0， 失败返回-1， 接收未完成返回1
//  */
//int receive_result_of_stunnel(CLIENT_INFO_T *clientInfo)
//{
//	int	  retval;
//	/// 接收openvpn配置
//	RECV_FILE(clientInfo->serverFd);
//
//	clientInfo->relayData.data = clientInfo->fileInfo.buffer+4;
//	retval = generate_stunnel_config(clientInfo);
//	clientInfo->relayData.data = NULL;
//	clientInfo->relayData.head = IDX_VPN_UTUNNEL;
//cleanup:
//	if (clientInfo->fileInfo.buffer)
//	{
//		free(clientInfo->fileInfo.buffer);
//		clientInfo->fileInfo.buffer   = NULL;
//		clientInfo->fileInfo.length   = 0;
//		clientInfo->fileInfo.position = 0;
//	}
//
//	return 0;
//}
//
///**
//  * @brief   发送stunnel请求
//  * @param   arg1 客户端信息结构体
//  * @retval  成功返回0，失败返回-1，发送未完成返回1
//  */
//int send_request_of_stunnel(CLIENT_INFO_T *clientInfo)
//{
//	int retval;
//	if (clientInfo->bufferFirst == YES)
//	{
//		ZeroMemory(clientInfo->buffer, SOCK_RECV_MAXBUF);
//		sprintf(clientInfo->buffer, "%4d%4d", 4, IDX_VPN_STUNNEL);
//		clientInfo->bufferLength = strlen(clientInfo->buffer);
//		clientInfo->bufferPosition = 0;
//	}
//
//	SEND_COMMAND(clientInfo->serverFd);
//}
//
///**************************************** openvpn ***************************************/
#define GET_RAND() (srand((unsigned int)time(NULL)), rand() % 60000 + 1024)

/**
  * @brief   获取VPN配置信息
  * @param   arg1 客户端信息结构体
  * @retval  0 成功  -1 失败
  */
int generate_openvpn_config(CLIENT_INFO_T *clientInfo)
{
    FILE		   *fp							= NULL;
	char		   *temp						= NULL;
	char           *savep						= NULL;
	char		   tempBuffer[SOCK_RECV_MAXBUF] = {0};
	char           openvpn_pass_conf_buf[64]    = {0};
    const char     * commomName                 = "sonicomT";
	char           *client_config_path          = "./config/";
	OPENVPN_INFO_T	openvpn_info;

    MSG_DEBUG("[generate_openvpn_config] relayData info##%s", (char *)clientInfo->relayData.data);
	sprintf(tempBuffer, "%s", (char *)clientInfo->relayData.data);
	openvpn_info.port  = strtok_r(tempBuffer, ":", &savep);
	openvpn_info.proto = strtok_r(NULL, ":", &savep);
	temp = strtok_r(NULL, ":", &savep);
	openvpn_info.cipher = !strcmp(temp, "null")   ? NULL : temp;
	temp = strtok_r(NULL, ":", &savep);
	openvpn_info.auth = !strcmp(temp, "null")     ? NULL : temp;
	temp = strtok_r(NULL, ":", &savep);
	openvpn_info.tun_mtu = !strcmp(temp, "null")  ? NULL : temp;
	temp = strtok_r(NULL, ":", &savep);
	openvpn_info.fragment = !strcmp(temp, "null") ? NULL : temp;
	temp = strtok_r(NULL, ":", &savep);
	openvpn_info.mssfix = !strcmp(temp, "null")   ? NULL : temp;
	temp = strtok_r(NULL, ":", &savep);
	openvpn_info.tls_auth = !strcmp(temp, "null") ? NULL : temp;

    sprintf(openvpn_pass_conf_buf, "%spass.conf", client_config_path);
	fp = fopen(openvpn_pass_conf_buf, "wt");
	//fputs(clientInfo->commomName, fp);
	fputs(commomName, fp);
	fputs("\n************", fp);
	fclose(fp);
	ZeroMemory(clientInfo->buffer, SOCK_RECV_MAXBUF);
	snprintf(clientInfo->buffer, SOCK_RECV_MAXBUF,
        /******************* 固定参数 */
        //"management %scache/mgmtsocket unix\n"
        //"management-client\n"
        //"management-query-passwords\n"
        //"management-hold\n"
        //"setenv IV_GUI_VER \"de.blinkt.openvpn 0.6.13\"\n"
        //"nobind\n"
        //"machine-readable-output\n"
        //"connect-retry-max 6\n"
        //"connect-retry 6\n"
        //"resolv-retry 60\n"

        "comp-lzo\n"
        "client\n"
        "verb 4\n"
        "dev tun\n"
        "auth-user-pass %spass.conf\n"
        "persist-tun\n"
        "persist-key\n"
        "ca %sca.crt\n"
        "key %sclient.key\n"
        "cert %sclient.crt\n"
        "log %ssonicomEncryptVpn.log\n"
        /******************* 可变参数 */
        "remote %s \n"
        "port %s \n"
        "proto %s \n",
        client_config_path,
        client_config_path,
        client_config_path,
        client_config_path,
        client_config_path,
        clientInfo->serverIp,
        openvpn_info.port,
        openvpn_info.proto );
    /******************* 可选参数 */
    if (openvpn_info.cipher)
    {
        strcat(clientInfo->buffer, "\n--cipher ");
        strcat(clientInfo->buffer, openvpn_info.cipher);
    }
    if (openvpn_info.auth)
    {
        strcat(clientInfo->buffer, "\nauth ");
        strcat(clientInfo->buffer, openvpn_info.auth);
    }
    if (openvpn_info.tun_mtu)
    {
        strcat(clientInfo->buffer, "\ntun-mtu ");
        strcat(clientInfo->buffer, openvpn_info.tun_mtu);
    }
    if (openvpn_info.fragment)
    {
        strcat(clientInfo->buffer, "\nfragment ");
        strcat(clientInfo->buffer, openvpn_info.fragment);
    }
    if (openvpn_info.mssfix)
    {
        strcat(clientInfo->buffer, "\nmssfix ");
        strcat(clientInfo->buffer, openvpn_info.mssfix);
    }
    if (openvpn_info.tls_auth)
    {
        strcat(clientInfo->buffer, "\ntls-auth ");
        strcat(clientInfo->buffer, client_config_path);
        strcat(clientInfo->buffer, "sonicom.key 0");
    }
    fp = fopen(openvpn_config_path, "wt");
    fputs(clientInfo->buffer, fp);
	fflush(fp);
    fclose(fp);
	return 0;
}

/**
  * @brief   启动openvpn进
  * @param   arg1 客户端信息结构体
  * @retval  成功返回0， 失败返回-1， 接收未完成返回1
  */
int startup_vpn(CLIENT_CONFIG_T * clientConfig)
{
    //fork
    pid_t pid;
    //char * args[] = {"--config", "./client.conf", NULL};
    char * args[] = {"--config", clientConfig->vpnConfigPath, NULL};

    pid = fork();
    if(pid > 0)
    {
        //*pid_r = pid;
        MSG(LOG_DEBUG, "[startup_vpn] get child process id is ##%d", pid);
        //father
    }
    else if (pid == 0)
    {
        //child
        //assert(-1 != execv("./openvpn",args));
        MSG(LOG_DEBUG, "[startup_vpn] vpnbin is  ##%s and config is ##%s", clientConfig->vpnBin, clientConfig->vpnConfigPath );
        assert_param( -1 != execv(clientConfig->vpnBin, args) );

    }
    else
    {
        //error
        MSG(LOG_ERROR, "[startup_vpn] fork error");
        return -1;
    }
    return 0;
}
/**
  * @brief   接收openvpn结果
  * @param   arg1 客户端信息结构体
  * @retval  成功返回0， 失败返回-1， 接收未完成返回1
  */
int receive_result_of_openvpn(CLIENT_INFO_T *clientInfo, CLIENT_CONFIG_T *clientConfig)
{
	int	  retval;
	//pid_t pid;

	/// 接收openvpn配置
	RECV_FILE(clientInfo->serverFd);

	clientInfo->relayData.data = clientInfo->fileInfo.buffer+4;
	assert(0== generate_openvpn_config(clientInfo));
	if ((PACK_HEAD_T)PackHead == IDX_VPN_BOTH)
	{
		//clientInfo->relayData.data = NULL;
		//clientInfo->relayData.head = IDX_VPN_STUNNEL;
		;
	}
	else
	{
		//startup_all_services(clientInfo);
		//retval = startup_openvpn(&pid);
		retval = startup_vpn( clientConfig );
		MSG( LOG_DEBUG, "[receive_result_of_vpn] fork and startup openvpn" );

	}
    clientInfo->relayData.data = NULL;
    clientInfo->relayData.head = IDX_VPN_HEARTBEAT_TIMEOUT;


cleanup:
	if (clientInfo->fileInfo.buffer)
	{
		free(clientInfo->fileInfo.buffer);
		clientInfo->fileInfo.buffer   = NULL;
		clientInfo->fileInfo.length   = 0;
		clientInfo->fileInfo.position = 0;
	}

	return retval;
}

/**
  * @brief   发送openvpn请求
  * @param   arg1 客户端信息结构体
  * @retval  成功返回0，失败返回-1，发送未完成返回1
  */
int send_request_of_openvpn(CLIENT_INFO_T *clientInfo)
{
	int retval;

	if (clientInfo->bufferFirst == YES)
	{
		ZeroMemory(clientInfo->buffer, SOCK_RECV_MAXBUF);
		sprintf(clientInfo->buffer, "%4d%4d", 4, IDX_VPN_OPENVPN);
		clientInfo->bufferLength = strlen(clientInfo->buffer);
		clientInfo->bufferPosition = 0;
	}

	SEND_COMMAND(clientInfo->serverFd);
}

///* ********************************** APPTYPE ********************************** */
///**
//  * @brief   接收vpntype结果
//  * @param   arg1 客户端信息结构体
//  * @retval  成功返回0， 失败返回-1， 接收未完成返回1
//  */
//int receive_result_of_apptype(CLIENT_INFO_T *clientInfo)
//{
//	int			retval;
//	DATA_PACK_T  *datapack;
//
//	RECV_COMMAND(clientInfo->serverFd);
//
//	if (datapack->head != IDX_VPN_APPTYPE)
//	{
//		__android_log_write(ANDROID_LOG_ERROR, "dragon", "[receive_result_of_bind] Get unexpecting data!");
//		return -1;
//	}
//
//	clientInfo->relayData.data = NULL;
//	PackHead = atoi(datapack->buffer);
//	if ((PACK_HEAD)PackHead == IDX_VPN_NONE)
//	{
//		send_message_to_java(SUCCESS_LOGINED_SERVER);
//		clientInfo->relayData.head = IDX_VPN_HEARTBEAT_TIMEOUT;
//	}
//	else if ((PACK_HEAD)PackHead == IDX_VPN_BOTH)
//	{
//		clientInfo->relayData.head = IDX_VPN_OPENVPN;
//	}
//	else
//	{
//		clientInfo->relayData.head = (PACK_HEAD)atoi(datapack->buffer);
//	}
//
//	/************** 移除配置文件 */
//	remove(openvpn_config_path);
//	remove(stunnel_config_path);
//	remove(utunnel_config_path);
//	remove(stunnel_recv_path);
//	remove(utunnel_recv_path);
//
//	return 0;
//}
//
///**
//  * @brief   发送vpntype请求
//  * @param   arg1 客户端信息结构体
//  * @retval  成功返回0，失败返回-1，发送未完成返回1
//  */
//int send_request_of_apptype(CLIENT_INFO_T *clientInfo)
//{
//	int retval;
//
//	if (clientInfo->bufferFirst == YES)
//	{
//		ZeroMemory(clientInfo->buffer, SOCK_RECV_MAXBUF);
//		sprintf(clientInfo->buffer, "%4d%4d", 4, IDX_VPN_APPTYPE);
//		clientInfo->bufferLength = strlen(clientInfo->buffer);
//		clientInfo->bufferPosition = 0;
//	}
//
//	SEND_COMMAND(clientInfo->serverFd);
//}
//
///* ********************************** BIND ********************************** */
/**
  * @brief   接收bind结果
  * @param   arg1 客户端信息结构体
  * @retval  成功返回0， 失败返回-1， 接收未完成返回1
  */
int receive_result_of_bind(CLIENT_INFO_T *clientInfo)
{
	int			retval;
	DATA_PACK_T  *datapack;

	RECV_COMMAND(clientInfo->serverFd);

	if (datapack->head != IDX_VPN_BIND)
	{
		return -1;
	}

	if (strcmp(datapack->buffer, CLIENT_POSITIVE) == 0)
	{
		clientInfo->relayData.data = NULL;
		//xiaohu mod 2016/02/26 //clientInfo->relayData.head = IDX_VPN_APPTYPE;
		//通过后门,请求IDX_VPN_ANDROID_DOOR，否则直接心跳
		//clientInfo->relayData.head = IDX_VPN_ANDROID_DOOR;

        clientInfo->relayData.head = IDX_VPN_OPENVPN;
		return 0;
	}

	return -1;
}

/**
  * @brief   发送bind请求
  * @param   arg1 客户端信息结构体
  * @retval  成功返回0，失败返回-1，发送未完成返回1
  */
int send_request_of_bind(CLIENT_INFO_T *clientInfo)
{
    int		retval;

	if (clientInfo->bufferFirst == YES)
	{
		ZeroMemory(clientInfo->buffer, SOCK_RECV_MAXBUF);
		clientInfo->bufferLength = strlen(clientInfo->bindInfo)+4;
		sprintf(clientInfo->buffer, "%4d%4d%s", clientInfo->bufferLength, IDX_VPN_BIND, clientInfo->bindInfo);
		clientInfo->bufferLength = strlen(clientInfo->buffer);
		clientInfo->bufferPosition = 0;
	}

	SEND_COMMAND(clientInfo->serverFd);
}

///* ********************************** SN ********************************** */
/**
  * @brief   接收SN结果
  * @param   arg1 客户端信息结构体
  * @retval  成功返回0， 失败返回-1， 接收未完成返回1
  */
int receive_result_of_sn(CLIENT_INFO_T *clientInfo)
{
	int			retval;
	DATA_PACK_T  *datapack;

	RECV_COMMAND(clientInfo->serverFd);

	if (datapack->head != IDX_VPN_SN)
	{
		return -1;
	}

	if ( strcmp(datapack->buffer, CLIENT_POSITIVE) == 0)
	{
		clientInfo->relayData.data = NULL;
        clientInfo->relayData.head = IDX_VPN_BIND;//IDX_VPN_OPENVPN;
		return 0;
	}

	return -1;
}

/**
  * @brief   发送SN请求
  * @param   arg1 客户端信息结构体
  * @retval  成功返回0，失败返回-1，发送未完成返回1
  */
int send_request_of_sn(CLIENT_INFO_T *clientInfo)
{
	int retval;

	if (clientInfo->bufferFirst == YES)
	{
		ZeroMemory(clientInfo->buffer, SOCK_RECV_MAXBUF);
		clientInfo->bufferLength = strlen(clientInfo->serialNumber)+4;
		sprintf(clientInfo->buffer, "%4d%4d%s", clientInfo->bufferLength, IDX_VPN_SN, clientInfo->serialNumber);
		clientInfo->bufferLength = strlen(clientInfo->buffer);
		clientInfo->bufferPosition = 0;
	}

	SEND_COMMAND(clientInfo->serverFd);
}

///* ********************************** X509 ********************************** */
/**
  * @brief   接收X509返回的结果
  * @param   arg1 客户端信息结构体
  * @retval  成功返回0， 失败返回-1， 接收未完成返回1
  */
int receive_result_of_x509(CLIENT_INFO_T *clientInfo)
{
	int			retval;
	DATA_PACK_T  *datapack;

	RECV_COMMAND(clientInfo->serverFd);

	if (datapack->head != IDX_VPN_X509)
	{
		return -1;
	}

	if ( strcmp(datapack->buffer, CLIENT_POSITIVE) == 0)
	{
		clientInfo->relayData.data = NULL;
		//clientInfo->relayData.head = IDX_VPN_OPENVPN;
		clientInfo->relayData.head = IDX_VPN_SN;
		return 0;
	}

	return -1;
}

/**
  * @brief   发送X509上下文
  * @param   aarg1 客户端信息结构体
  * @retval  成功返回0，失败返回-1，发送未完成返回1
  */
int send_request_of_x509(CLIENT_INFO_T *clientInfo)
{
	int	retval;

	if (clientInfo->bufferFirst == YES)
	{
		ZeroMemory(clientInfo->buffer, SOCK_RECV_MAXBUF);
        clientInfo->fileInfo.length   = clientInfo->x509Cert.length+8;
        clientInfo->fileInfo.position = 0;
        clientInfo->fileInfo.buffer   = (char *)calloc(clientInfo->fileInfo.length+1, 1);
        snprintf((char *)clientInfo->fileInfo.buffer,
                         clientInfo->fileInfo.length,
               "%4d%4d", clientInfo->x509Cert.length+4, IDX_VPN_X509);
        memcpy(clientInfo->fileInfo.buffer+8, clientInfo->x509Cert.context, clientInfo->x509Cert.length);
	}

	SEND_FILE(clientInfo->serverFd);
}

/* ********************************** VERSION ********************************** */
/**
  * @brief   接收版本结果
  * @param   arg1 客户端信息结构体
  * @retval  成功返回0， 失败返回-1， 接收未完成返回1， 需要更新返回2
  */
int receive_result_of_version(CLIENT_INFO_T *clientInfo)
{
	int			retval;
	DATA_PACK_T  *datapack;
	RECV_COMMAND(clientInfo->serverFd);

	if (datapack->head != IDX_VPN_VERSION)
	{
		return -1;
	}

	if (strcmp(datapack->buffer, "update") == 0)
	{
		//return 2;
		goto label_receive_result_of_version;
	}
label_receive_result_of_version:
	clientInfo->relayData.data = NULL;
    #ifdef ENABLE_NOT_IDX_VPN_X509
        clientInfo->relayData.head = IDX_VPN_SN;        //across the IDX_VPN_X509 step. vpnserver need ENABLE_NOT_IDX_VPN_X509 MODEL
    #else
        clientInfo->relayData.head = IDX_VPN_X509;    //debug the sequence of the program, use cert verify but server use not verify mode
    #endif

	//clientInfo->relayData.head =  IDX_VPN_OPENVPN;
	return 0;
}

/**
  * @brief   向服务器发送版本号
  * @param   arg1 客户端信息结构体
  * @retval  成功返回0，失败返回-1，发送未完成返回1
  */
int send_request_of_version(CLIENT_INFO_T *clientInfo)
{
	int retval;

	if (clientInfo->bufferFirst == YES)
	{
		ZeroMemory(clientInfo->buffer, SOCK_RECV_MAXBUF);
		clientInfo->bufferLength = strlen(LINUX_CLIENT_VERSION)+4;
		sprintf(clientInfo->buffer, "%4d%4d%s", clientInfo->bufferLength, IDX_VPN_VERSION, LINUX_CLIENT_VERSION);
		clientInfo->bufferLength = strlen(clientInfo->buffer);
		clientInfo->bufferPosition = 0;
	}

	SEND_COMMAND(clientInfo->serverFd);
}

/* ********************************** WELCOME ********************************** */
/**
  * @brief   接收服务器欢迎响应
  * @param   arg1 客户端信息结构体
  * @retval  成功返回0， 失败返回-1
  */
int receive_result_of_welcome(CLIENT_INFO_T *clientInfo)
{
	ZeroMemory(clientInfo->buffer, SOCK_RECV_MAXBUF);

	recv(clientInfo->serverFd, clientInfo->buffer, SOCK_RECV_MAXBUF, 0);
	if (streql(clientInfo->buffer, CLIENT_POSITIVE))
	{
		clientInfo->relayData.head = IDX_VPN_VERSION;
		clientInfo->bufferFirst = YES;
		return 0;
	}
	return -1;
}

/**
  * @brief   发送欢迎握手
  * @param   arg1 客户端信息结构体
  * @retval  发送成功返回0， 失败返回-1
  */
int send_request_of_welcome(CLIENT_INFO_T *clientInfo)
{
	int retval;

	retval = send(clientInfo->serverFd, SERVER_PASSWORD, SERVER_PSWDSIZE, 0);
	if (retval == SERVER_PSWDSIZE)
		return 0;
	return -1;
}




/******************* (C) COPYRIGHT 2018 上海今中网络科技有限公司 *****END OF FILE****/
